package io.dshubs.archives.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.dshubs.archives.dto.ArchiveNumberRuleDto;
import io.dshubs.archives.entity.ArchiveBaseInfo;
import io.dshubs.archives.entity.ArchiveBaseRule;
import io.dshubs.archives.dao.ArchiveBaseRuleMapper;
import io.dshubs.archives.service.ArchiveBaseInfoService;
import io.dshubs.archives.service.ArchiveBaseRuleService;
import io.dshubs.commons.mybatis.service.impl.BaseServiceImpl;
import io.dshubs.commons.security.context.TenantContext;
import io.dshubs.commons.security.user.SecurityUser;
import io.dshubs.commons.security.user.UserDetail;
import io.dshubs.commons.tools.constant.Constant;
import io.dshubs.commons.tools.exception.RenException;
import io.dshubs.commons.tools.page.PageData;
import io.dshubs.commons.tools.utils.ConvertUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 档号规则 服务实现类
 * </p>
 *
 * @author tan
 * @since 2021-08-16
 */
@Service
public class ArchiveBaseRuleServiceImpl extends BaseServiceImpl<ArchiveBaseRuleMapper, ArchiveBaseRule> implements ArchiveBaseRuleService {

    @Autowired
    private ArchiveBaseInfoService archiveBaseInfoService;

    @Override
    public PageData<ArchiveBaseRule> page(Map<String, Object> params) {
        IPage<ArchiveBaseRule> iPage = getPage(params, Constant.CREATE_DATE, false);
        int pages = (int)iPage.getCurrent();
        int size = (int)iPage.getSize();
        String ruleName = (String) params.get("ruleName");
        PageData<ArchiveBaseRule> pageData = new PageData<>();
        UserDetail user = SecurityUser.getUser();
        QueryWrapper<ArchiveBaseRule> wrapper = new QueryWrapper<ArchiveBaseRule>().eq("tenant_code", TenantContext.getTenantCode(user));
        if(StringUtils.isNotEmpty(ruleName)) {
            wrapper.like("rule_name", ruleName);
        }
        wrapper.groupBy("archive_id").select("archive_id");
        List<ArchiveBaseRule> archiveBaseRuleList = this.baseDao.selectList(wrapper);

        if(CollectionUtils.isEmpty(archiveBaseRuleList)) {
            pageData.setList(archiveBaseRuleList);
            pageData.setTotal(0);
        } else {
            int listSize = archiveBaseRuleList.size();
            List<ArchiveBaseRule> baseRuleList = archiveBaseRuleList.subList(Math.min((pages - 1) * size, listSize), Math.min(pages * size, listSize));
            List<Long> ids = baseRuleList.stream().map(ArchiveBaseRule::getArchiveId).collect(Collectors.toList());
            List<ArchiveBaseRule> res = new ArrayList<>();
            List<ArchiveBaseRule> newArchiveBaseRule = this.baseDao.selectList(new QueryWrapper<ArchiveBaseRule>().in("archive_id", ids));

            Map<Long, List<ArchiveBaseRule>> nameGroup = newArchiveBaseRule.stream()
                    .collect(Collectors.groupingBy(ArchiveBaseRule::getArchiveId, Collectors.toList()));
            nameGroup.forEach((k,v)->{
                ArchiveBaseRule sr = ConvertUtils.sourceToTarget(v.get(0), ArchiveBaseRule.class);
                sr.setRule(v.stream().map(i->{
                    if("FIELD_JOINT".equals(i.getLabel())) {
                        i.setLabel(i.getValue());
                    }
                    return i.getLabel();
                }).collect(Collectors.joining("")));
                ArchiveBaseInfo archiveBaseInfo = archiveBaseInfoService.selectById(k);
                sr.setGeneralArchiveInfoName(archiveBaseInfo == null ? "": archiveBaseInfo.getName());
                res.add(sr);
            });

            pageData.setList(res);
            pageData.setTotal(res.size());
        }

        return pageData;
    }

    @Override
    public void save(ArchiveNumberRuleDto archiveNumberRuleDto) {

        String ruleName = archiveNumberRuleDto.getRuleName();
        String oldRuleName = archiveNumberRuleDto.getOldRuleName();
        Long generalArchiveInfoId = archiveNumberRuleDto.getArchiveId();
        List<ArchiveNumberRuleDto.Rule> ruleList = archiveNumberRuleDto.getRuleList();

        if(CollectionUtils.isEmpty(ruleList)
                || findByGeneralArchiveId(archiveNumberRuleDto.getArchiveId(),ruleName).size() > 0
        ) {
            throw new RenException("系统已经存在规则名称"+ruleName + "或该全宗id已经存在规则，请删除或修改");
        }

        if(oldRuleName == null){
            List<ArchiveBaseRule> sysFileRuleList = ConvertUtils.sourceToTarget(ruleList, ArchiveBaseRule.class);
            assert sysFileRuleList != null;
            sysFileRuleList.forEach(rule -> {
                rule.setArchiveId(generalArchiveInfoId);
                rule.setRuleName(ruleName);
                this.baseDao.insert(rule);
            });

        } else {
            List<ArchiveBaseRule> oldSysFileRuleList = findByGeneralArchiveId(archiveNumberRuleDto.getArchiveId(),ruleName);
            List<Long> ids = oldSysFileRuleList.stream().map(ArchiveBaseRule::getId).collect(Collectors.toList());
            this.baseDao.deleteBatchIds(ids);
            archiveNumberRuleDto.setOldRuleName(null);
            save(archiveNumberRuleDto);
        }
    }

    @Override
    public void deleteByName(List<Long> ids) {
        List<ArchiveBaseRule> archiveBaseRules = this.baseDao.selectBatchIds(ids);
        List<String> stringList = archiveBaseRules.stream().distinct().map(ArchiveBaseRule::getRuleName).collect(Collectors.toList());
        List<Long> archiveIdList = archiveBaseRules.stream().distinct().map(ArchiveBaseRule::getArchiveId).collect(Collectors.toList());
        this.baseDao.delete(new QueryWrapper<ArchiveBaseRule>().in("rule_name",stringList).in("archive_id",archiveIdList));
    }

    private List<ArchiveBaseRule> findByGeneralArchiveId(Long generalArchiveId,String ruleName) {
        return this.baseDao.selectList(new QueryWrapper<ArchiveBaseRule>().eq("archive_id",generalArchiveId)
                .or().eq("rule_name",ruleName)
        );
    }

    @Override
    public List<ArchiveBaseRule> list() {
        List<ArchiveBaseRule> repeatArchiveBaseRuleList = this.baseDao.selectList(null);
        List<ArchiveBaseRule> noRepeatArchiveBaseRuleList = repeatArchiveBaseRuleList.stream().filter(distinctByKey(ArchiveBaseRule::getRuleName)).collect(Collectors.toList());

        return noRepeatArchiveBaseRuleList;
    }
    public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> map = new ConcurrentHashMap<>(16);
        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

}
